﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using LogLib;
using System.Threading.Tasks;

namespace KAImage.Algorithms
{     
    /// <summary>
    /// 图像直方图计算服务
    /// </summary>
    public class ImageHistograms
    {
        #region static fields
        private static ImageHistograms instance;

        private static object _lock = new object();

        public static ImageHistograms GetInstance()
        {
            if (instance == null)
            {
                lock (_lock)
                {
                    if (instance == null)
                    {
                        instance = new ImageHistograms();
                    }
                }
            }
            return instance;
        }

        public static int GetMedianNumber(int[] data)
        {
            if (data == null)
            {
                return 1;
            }
            if (data.Length == 1)
            {
                return data[0];
            }
            int[] copyData = data.Clone() as int[];
            Array.Sort(copyData);

            // 去掉首尾重复的最小值和最大值
            int max = copyData.Last();
            int min = copyData.First();

            int begin = Array.LastIndexOf(copyData, min);
            int end = Array.IndexOf(copyData, max);
            int n = end - begin + 1;

            int[] realData = copyData.Skip(begin).Take(n).ToArray();

            if (n % 2 == 0)
            {
                return (realData[n / 2 - 1] + realData[n / 2]) / 2;
            }
            if (n % 2 == 1)
            {
                return realData[n / 2];
            }
            return 0;
        }

        /// <summary>
        /// 获取图像三个分量的直方图数据
        /// </summary>
        /// <param name="srcBmp">图像</param>
        /// <param name="hR">R分量直方图数据</param>
        /// <param name="hG">G分量直方图数据</param>
        /// <param name="hB">B分量直方图数据</param>
        public static void GetHistogramRGBChannel(Bitmap srcBmp, int[] hR, int[] hG, int[] hB)
        {
            if (srcBmp == null)
            {
                return;
            }
            //灰度等级数组清零
            Array.Clear(hR, 0, 256);
            Array.Clear(hB, 0, 256);
            Array.Clear(hG, 0, 256);

            BitmapData bmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr = null;
                for (int i = 0; i < srcBmp.Height; i++)
                {
                    ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
                    for (int j = 0; j < srcBmp.Width; j++)
                    {
                        hB[ptr[j * 3]]++;
                        hG[ptr[j * 3 + 1]]++;
                        hR[ptr[j * 3 + 2]]++;
                    }
                }
            }
            srcBmp.UnlockBits(bmpData);
        }

        /// <summary>
        /// 获取图像灰度直方图数据
        /// </summary>
        /// <param name="srcBmp">图像</param>
        /// <param name="hRGB">全图直方图数据</param>
        public static void GetHistogramRGB(Bitmap srcBmp, int[] hRGB)
        {
            if (srcBmp == null)
            {
                return;
            }
            Array.Clear(hRGB, 0, 256);
            BitmapData bmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr = null;
                for (int i = 0; i < srcBmp.Height; i++)
                {
                    ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
                    for (int j = 0; j < srcBmp.Width; j++)
                    {
                        hRGB[ptr[j * 3]]++;
                        hRGB[ptr[j * 3 + 1]]++;
                        hRGB[ptr[j * 3 + 2]]++;
                    }
                }
            }
            srcBmp.UnlockBits(bmpData);
        }

        /// <summary>
        /// 获取图像三个分量的直方图数据
        /// </summary>
        /// <param name="srcBmp">图像</param>
        /// <param name="hRGB">全图直方图数据</param>
        /// <param name="hR">R分量直方图数据</param>
        /// <param name="hG">G分量直方图数据</param>
        /// <param name="hB">B分量直方图数据</param>
        public static void GetBitmapHistogram(Bitmap srcBmp, int[] hRGB, int[] hR, int[] hG, int[] hB)
        {
            if (srcBmp == null)
            {
                return;
            }
            //灰度等级数组清零
            Array.Clear(hR, 0, 256);
            Array.Clear(hB, 0, 256);
            Array.Clear(hG, 0, 256);
            Array.Clear(hRGB, 0, 256);
            BitmapData bmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr = null;
                for (int i = 0; i < srcBmp.Height; i++)
                {
                    ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
                    for (int j = 0; j < srcBmp.Width; j++)
                    {
                        hRGB[ptr[j * 3]]++;
                        hRGB[ptr[j * 3 + 1]]++;
                        hRGB[ptr[j * 3 + 2]]++;
                        hB[ptr[j * 3]]++;
                        hG[ptr[j * 3 + 1]]++;
                        hR[ptr[j * 3 + 2]]++;
                    }
                }
            }
            srcBmp.UnlockBits(bmpData);
        }

        #endregion

        private int[] _hR = new int[256];
        public int[] hR
        {
            get { return _hR; }
        }

        private int[] _hG = new int[256];
        public int[] hG
        {
            get { return _hG; }
        }

        private int[] _hB = new int[256];
        public int[] hB
        {
            get { return _hB; }
        }

        private int[] _hRGB = new int[256];
        public int[] hRGB
        {
            get { return _hRGB; }
        }

        //对于所有像素点颜色分布直方图频率中位数    
        private int _nMedianPixel = 1;
        public int nMedianPixel
        {
            get { return _nMedianPixel; }
            set { _nMedianPixel = value; }
        }

        // 对于单通道颜色像素的直方图分布频率中位数     
        private int _nChannelMedianPixel = 1;
        public int nChannelMedianPixel
        {
            get { return _nChannelMedianPixel; }
            set { _nChannelMedianPixel = value; }
        }

        public ImageHistograms()
        {
           
        }

        private void ClearData()
        {
            Array.Clear(_hRGB, 0, _hRGB.Length);
            Array.Clear(_hR, 0, _hR.Length);
            Array.Clear(_hG, 0, _hG.Length);
            Array.Clear(_hB, 0, _hB.Length);
        }

        /// <summary>
        /// 计算图像的直方图
        /// </summary>
        /// <param name="source"></param>
        public void CalculateHistograms(Bitmap source)
        {
            ClearData();
            if (source == null)
            {
                return;
            }
            int m0=0, m1=0, m2=0;
            try
            {
                GetBitmapHistogram(source, _hRGB, _hR, _hG, _hB);
                //对于所有像素点颜色分布直方图频率中位数    
                Parallel.Invoke(
                    () => { nMedianPixel = GetMedianNumber(_hRGB) * 6; },
                    () => { m0 = GetMedianNumber(_hR); },
                    () => { m1 = GetMedianNumber(_hG); },
                    () => { m2 = GetMedianNumber(_hB); });  
                // 对于单通道颜色像素的直方图分布频率中位数     
                nChannelMedianPixel = (m0 + m1 + m2) / 3 * 12;               
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
        }
    }

    public enum ColorChannel : int
    {
        RGB = 0,
        R = 1,
        G = 2,
        B = 3,
        //Alpha = 3,      
    }
}
